import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

// 烟花显示面板，继承自JPanel，用于绘制烟花效果
public class Fireworks extends JPanel {
    private static final int WIDTH = 800;  // 面板宽度
    private static final int HEIGHT = 600; // 面板高度
    private static final int FPS = 60;    // 每秒帧数
    private static final Random random = new Random(); // 随机数生成器
    private final List<Firework> fireworks;     // 存储当前的烟花列表

    // 构造函数，初始化烟花列表，并设置面板的偏好大小和背景颜色
    public Fireworks() {
        fireworks = new ArrayList<>();
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
    }

    // 主函数，创建并显示主窗口，启动烟花更新线程
    public static void main(String[] args) {
        JFrame frame = new JFrame("Fireworks"); // 创建主窗口
        Fireworks fireworksPanel = new Fireworks(); // 创建烟花显示面板
        frame.add(fireworksPanel); // 将面板添加到窗口中
        frame.pack(); // 调整窗口大小以适应面板大小
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗口关闭操作
        frame.setLocationRelativeTo(null); // 窗口居中显示
        frame.setVisible(true); // 显示窗口

        // 启动一个新线程，用于更新烟花状态和重绘面板
        new Thread(() -> {
            while (true) {
                fireworksPanel.update(); // 更新烟花状态
                try {
                    Thread.sleep(1000 / FPS); // 控制帧率
                } catch (InterruptedException e) {
                    e.printStackTrace(); // 捕获线程中断异常
                }
                SwingUtilities.invokeLater(fireworksPanel::repaint); // 在事件调度线程中重绘面板
            }
        }).start();
    }

    // 更新烟花状态，包括移除已爆炸的烟花和生成新烟花
    public void update() {
        fireworks.removeIf(firework -> firework.isExploded()); // 移除已爆炸的烟花
        if (random.nextInt(100) < 5) {  // 每次循环有5%的概率发射一个烟花
            fireworks.add(new Firework(random.nextInt(WIDTH), HEIGHT)); // 创建并添加新烟花
        }
        for (Firework firework : fireworks) {
            firework.update(); // 更新每个烟花的状态
        }
    }

    // 重写paintComponent方法，用于绘制烟花效果
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // 调用父类方法进行初始化
        Graphics2D g2d = (Graphics2D) g; // 获取Graphics2D对象用于高级绘制
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 开启抗锯齿
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, WIDTH, HEIGHT); // 绘制背景

        for (Firework firework : fireworks) {
            firework.draw(g2d); // 绘制每个烟花
        }
    }

    // 烟花类，包含烟花的位置、颜色、状态和粒子列表
    private static class Firework {
        private int x, y;
        private boolean isExploding = false;
        private Color color;
        private List<Particle> particles;

        public Firework(int x, int y) {
            this.x = x;
            this.y = y;
            this.color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)); // 随机颜色
            particles = new ArrayList<>();
        }

        // 更新烟花状态，包括上升和爆炸
        public void update() {
            if (!isExploding) {
                y -= 5;  // 烟花上升
                if (y < HEIGHT / 2) {
                    isExploding = true;  // 达到一定高度后爆炸
                    // 生成爆炸粒子，每个粒子有一个随机的角度
                    for (int i = 0; i < 100; i++) {
                        double theta = 2 * Math.PI * i / 100; // 计算角度
                        particles.add(new Particle(x, y, color, theta));
                    }
                }
            } else {
                for (Particle particle : particles) {
                    particle.update(); // 更新每个粒子的状态
                }
            }
        }

        // 绘制烟花，包括上升状态和爆炸状态
        public void draw(Graphics2D g2d) {
            if (!isExploding) {
                g2d.setColor(Color.WHITE);
                g2d.fillOval(x - 1, y - 1, 3, 3); // 绘制上升状态的烟花
            } else {
                for (Particle particle : particles) {
                    particle.draw(g2d); // 绘制爆炸状态的粒子
                }
            }
        }

        // 判断烟花是否完全爆炸，即所有粒子都已消失
        public boolean isExploded() {
            return isExploding && particles.isEmpty();
        }
    }

    // 烟花粒子类，包含粒子的位置、角度、速度、颜色和生命周期
    private static class Particle {
        private int x, y;
        private double theta; // 角度
        private double radius; // 半径
        private Color color;
        private int life = 50; // 生命周期
        private static final int MAX_RADIUS = 50; // 最大半径
        private static final double SPEED = 0.1; // 角度变化速度

        public Particle(int x, int y, Color color, double theta) {
            this.x = x;
            this.y = y;
            this.color = color;
            this.theta = theta; // 初始角度
            this.radius = 1; // 初始半径
        }

        // 更新粒子状态，包括位置和生命周期
        public void update() {
            // 根据角度更新位置
            radius += SPEED; // 增加半径
            double r = MAX_RADIUS * (1 - Math.sin(theta));
            x = (int) (x + r * Math.cos(theta));
            y = (int) (y - r * Math.sin(theta));

            theta += 0.1; // 增加角度
            life--; // 减少生命周期
            if (life <= 0) {
                // 移除粒子
            }
        }

        // 绘制粒子，仅在生命周期大于0时绘制
        public void draw(Graphics2D g2d) {
            if (life > 0) {
                g2d.setColor(color); // 设置粒子颜色
                g2d.fillOval(x - life / 2, y - life / 2, life, life); // 绘制粒子
            }
        }
    }
}
